package com.zwh.dianzong;

import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;

/**
 * 电总协议 response解析工具类
 * @author zwh
 * @date 2023-9-7 14:36
 */
@Slf4j
public class DianZongUtils {
    public static final String RTN_HEX_SUCCESS = "00";
    /**
     * 协议的头部，十六进制代码为 0x7E，对应ASCII码的字符：~
     */
    public static final String PROTOCOL_HEADER_SOI_HEX = "7E";
    /**
     * ASCII码的字符：CR, 对应变量中回车的符号 \r，十六进制代码为 0x0D
     */
    public static final String PROTOCOL_LAST_EOI_HEX= "0D";

    /**
     * 是否是电总协议
     * @param input tcp协议传输的字节流数据
     * @return
     */
    public static boolean isDianZongProtocol(byte[] input) {
        String hexStr = HexUtils.bytesToHexString(input);
        log.info("response data:"+ hexStr);

        String soi = hexStr.substring(0, 2);
        String eoi = hexStr.substring(hexStr.length()-2);

        if (!PROTOCOL_HEADER_SOI_HEX.equals(soi) || !PROTOCOL_LAST_EOI_HEX.equals(eoi)) {
            log.info("非电总协议，SOI:{}, EOI:{}", soi, eoi);
            return false;
        }
        return true;
    }

    public static DianZongResponseMessage parseResponse(byte[] input, DianZongVersionEnum versionEnum) {
        if (versionEnum == DianZongVersionEnum.V1_0) {
            return parseV1Response(HexUtils.bytesToHexString(input));
        } else if (versionEnum == DianZongVersionEnum.V1_5) {
            return parseV15Response(HexUtils.bytesToHexString(input));
        } else {
            throw new RuntimeException("未支持的电总协议版本号，请联系管理人员！");
        }
    }

    public static DianZongRequestMessage parseRequest(byte[] input, DianZongVersionEnum versionEnum) {
        return parseV1Request(HexUtils.bytesToHexString(input));
    }

    private static DianZongRequestMessage parseV1Request(String hexStr) {
        DianZongRequestMessage request = new DianZongRequestMessage();
        String soi = hexStr.substring(0, 2);
        String eoi = hexStr.substring(hexStr.length()-2);
        if (!PROTOCOL_HEADER_SOI_HEX.equals(soi) || !PROTOCOL_LAST_EOI_HEX.equals(eoi)) {
            log.info("非电总协议，SOI:{}, EOI:{}", soi, eoi);
            return null;
        }
        request.setProtocolVersion(DianZongVersionEnum.V1_0.name());

        request.setVer(HexUtils.hexStringToHexAscii(hexStr.substring(2, 6)));
        request.setAdr(HexUtils.hexStringToHexAscii(hexStr.substring(6, 10)));
        request.setCid1(HexUtils.hexStringToHexAscii(hexStr.substring(10, 14)));
        request.setCid2(HexUtils.hexStringToHexAscii(hexStr.substring(14, 18)));

        int dataInfoStart = 26;
        int dataInfoEnd = hexStr.length() - 10;
        String dataInfo = hexStr.substring(dataInfoStart, dataInfoEnd);
        request.setInfo(HexUtils.hexStringToHexAscii(dataInfo));

        String chkSum = HexUtils.hexStringToHexAscii(hexStr.substring(hexStr.length() - 10, hexStr.length()-2));
        request.setChkSum(chkSum);
        return request;
    }

    /**
     * 响应的十六进制数据结果解析成response数据
     * @param hexStr
     * @return
     */
    public static DianZongResponseMessage parseV1Response(String hexStr) {

        String soi = hexStr.substring(0, 2);
        String eoi = hexStr.substring(hexStr.length()-2);
        if (!PROTOCOL_HEADER_SOI_HEX.equals(soi) || !PROTOCOL_LAST_EOI_HEX.equals(eoi)) {
            log.info("非电总协议，SOI:{}, EOI:{}", soi, eoi);
            return null;
        }
        DianZongResponseMessage response = new DianZongResponseMessage();
        response.setProtocolVersion(DianZongVersionEnum.V1_0.name());

        response.setVer(HexUtils.hexStringToHexAscii(hexStr.substring(2, 6)));
        response.setAdr(HexUtils.hexStringToHexAscii(hexStr.substring(6, 10)));
        response.setCid1(HexUtils.hexStringToHexAscii(hexStr.substring(10, 14)));
        response.setRtn(HexUtils.hexStringToHexAscii(hexStr.substring(14, 18)));
        if (!response.getRtn().equals(RTN_HEX_SUCCESS)) {
            log.error("无效的连接响应：{}", response.getRtn());
            return null;
        }

        int dataInfoStart = 26;
        int dataInfoEnd = hexStr.length() - 10;
        String dataInfo = hexStr.substring(dataInfoStart, dataInfoEnd);
        response.setDataInfo(HexUtils.hexStringToHexAscii(dataInfo));

        String chkSum = HexUtils.hexStringToHexAscii(hexStr.substring(hexStr.length() - 10, hexStr.length()-2));
        response.setChkSum(chkSum);
        return response;
    }

    /**
     * 电总协议V1.5，在v1.0的基础上，多了一个dataFlag标志位
     * @param hexStr
     * @return
     */
    private static DianZongResponseMessage parseV15Response(String hexStr) {
        DianZongResponseMessage response = parseV1Response(hexStr);
        if (response == null) {
            return null;
        }
        response.setProtocolVersion(DianZongVersionEnum.V1_5.name());

        String dataInfo = HexUtils.hexAsciiToHexString(response.getDataInfo().toCharArray());
        if (dataInfo.length() > 0) {
            // 8 bit位表示dataFlag,2个ASCII字符，相当于截取长度为4的hex字符串，比如30 31
            // String dataFlag = dataInfo.substring(0, 4);
            response.setDataFlag(HexUtils.hexStringToHexAscii(dataInfo.substring(0, 4)));
        }
        // 其余都是信息
        response.setDataInfo(HexUtils.hexStringToHexAscii(dataInfo.substring(4)));
        return response;
    }

    /**
     * 电总协议中的Ascii形式表示的hex字符串 转为 浮点型-单精度 <br/>
     * 单精度Float -- 4字节 <br/>
     * 四个字节的浮点数据传送顺序为先低字节后高字节，所以需要对数据进行倒置，<br/>
     * 比如：67 E6 C6 43,要倒置成43 C6 E6 67，然后再进行hex转浮点型 <br/>
     * @param hexAsciiStr Ascii形式表示的hex字符串，长度为8位，比如：67 E6 C6 43
     * @return
     */
    public static BigDecimal castFloat(String hexAsciiStr) {
        if (hexAsciiStr == null || hexAsciiStr.length() != 8) {
            log.error("电总协议，要转换为Float单精度浮点型的hex长度错误，hexStr:{}", hexAsciiStr);
            return null;
        }
        char[] array = hexAsciiStr.toCharArray();
        StringBuilder realHexData = new StringBuilder();
        for (int i = 4; i > 0; i--) {
            realHexData.append(array[2 * i - 2]).append(array[2 * i - 1]);
        }
        return new BigDecimal(String.valueOf(HexUtils.castToFloat(realHexData.toString())));
    }

    /**
     * 将Ascii形式表示的hex字符串 转为 整型 <br/>
     * 整型Integer -- 2字节 <br/>
     * 数据传送顺序为先高字节后低字节, 直接进行hex到int类型的转换
     * @param hexAsciiStr Ascii形式表示的hex字符串，长度为4位，比如：67 E6
     * @return
     */
    public static Integer castInteger(String hexAsciiStr) {
        if (hexAsciiStr == null || hexAsciiStr.length() != 4) {
            log.error("电总协议，要转换为Integer整型的hex长度错误，hexStr:{}", hexAsciiStr);
            return null;
        }
        int length = hexAsciiStr.length();
        char[] data = hexAsciiStr.toCharArray();
        int sum = 0;
        for (int i = hexAsciiStr.length() - 1; i >= 0; i--) {
            int power = length - i - 1;
            char digit = data[i];
            sum += castCharToInt(digit) * Math.pow(16, power);
        }
        return sum;
    }

    /**
     * 十六进制字符 转为 十进制 <br/>
     * 对应电总协议中类型：char -- 1字节
     * @param hexAsciiChar
     * @return
     */
    public static int castCharToInt(char hexAsciiChar){
        if(hexAsciiChar >= 'A' && hexAsciiChar <= 'F') {
            return 10 + hexAsciiChar - 'A';
        } else {
            return hexAsciiChar - '0';
        }
    }
}
